
import java.util.ArrayList;
import java.util.Iterator;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author jairo
 */
public class TablaAlgoritmoQ {
	
	private float[][][] tabla;
	
	TablaAlgoritmoQ(int i, int j){ //Donde i y j son cant de filas y columnas
		tabla = new float[i][j][4];
		for(int it = 0; it < i; it++){
			for(int it2 = 0; it2 < j; it2++){
				tabla[it][it2][0] = 0; // arriba
				tabla[it][it2][1] = 0; // derecha
				tabla[it][it2][2] = 0; // abajo
				tabla[it][it2][3] = 0; // izquierda
			}
		}
	}
	
	void setQValor(int i, int j, int accion, float qvalor){
		tabla[i][j][accion] = qvalor;
	}
	
	float getQValor(int i, int j, int accion){
		return tabla[i][j][accion];
	}
	
	float getQValorMax(int i, int j) {

		if (i == 0 && j == 0) {
			if (getQValor(i,j,1) > getQValor(i,j,2) ) {
				return getQValor(i,j,1);
			} else {
				return getQValor(i,j,2);
			}
		} else if(i == 0 && j == 5){
			if (getQValor(i,j,3) > getQValor(i,j,2) ) {
				return getQValor(i,j,3);
			} else {
				return getQValor(i,j,2);
			}
		} else if(i == 5 && j == 0) {
			if (getQValor(i,j,0) > getQValor(i,j,1) ) {
				return getQValor(i,j,0);
			} else {
				return getQValor(i,j,1);
			}
		} else if(i == 5 && j == 5){
			if (getQValor(i,j,0) > getQValor(i,j,3) ) {
				return getQValor(i,j,0);
			} else {
				return getQValor(i,j,3);
			}	
		} else if (i == 0) {
			int maximo = 1;
			float qMaximo = getQValor(i, j, 1);
			for(int it = 2; it < 4; it++){
				if (qMaximo < getQValor(i, j, it)) {
					qMaximo = getQValor(i, j, it);
					maximo = it;
				}
			}
			return tabla[i][j][maximo];			
		} else if (i == 5) {
			int maximo = 3;
			float qMaximo = getQValor(i, j, 3);
			for(int it = 0; it < 2; it++){
				if (qMaximo < getQValor(i, j, it)) {
					qMaximo = getQValor(i, j, it);
					maximo = it;
				}
			}
			return tabla[i][j][maximo];		
		} else if (j == 0) {
			int maximo = 0;
			float qMaximo = getQValor(i, j, 0);
			for(int it = 1; it < 3; it++){
				if (qMaximo < getQValor(i, j, it)) {
					qMaximo = getQValor(i, j, it);
					maximo = it;
				}
			}
			return tabla[i][j][maximo];
		} else if (j == 5) {
			int maximo = 0;
			float qMaximo = getQValor(i, j, 0);
			for(int it = 2; it < 4; it++){
				if (qMaximo < getQValor(i, j, it)) {
					qMaximo = getQValor(i, j, it);
					maximo = it;
				}
			}
			return tabla[i][j][maximo];
		} else {
			int maximo = 0;
			float qMaximo = getQValor(i, j, 0);
			for(int it = 1; it < 4; it++){
				if (qMaximo < getQValor(i, j, it)) {
					qMaximo = getQValor(i, j, it);
					maximo = it;
				}
			}
			return tabla[i][j][maximo];	
		}		
	}
	
	void algoritmoQ(int episodios, float gamma, Mundo mundo){
		for(int i = 0; i < episodios; i++){
			ArrayList<ParAccionEstado> episodio = new ArrayList();
			// elijo estado al azar

			Estado estadoActual = mundo.elegirEAleatorio();
			
			boolean no_esObjetivo = true;
			
			while (no_esObjetivo) { //hasta llegar a goal
				// elijo accion
				int a = mundo.elegirAAleatoria(estadoActual);
				// ejecuto accion
				Estado siguiente = mundo.getEstado(estadoActual.getX(), estadoActual.getY(), a);
				// recivo recompensa
				float r = mundo.getReward(estadoActual.getX(), estadoActual.getY(), a);
				// actualizo Q(s,a)	
				this.setQValor(estadoActual.getX(), estadoActual.getY(), a,
								r + gamma*getQValorMax(siguiente.getX(),siguiente.getY()));	 /// esta mal es otra a'
				// guardo paso en el episodio
				ParAccionEstado paso = new ParAccionEstado(a, estadoActual.getX(), estadoActual.getY());
				episodio.add(0,paso);
				// paso al estado que me lleva la acción
				estadoActual = siguiente;
				//me fijo si llegué al objetivo
				if (mundo.getEsGoal(estadoActual)) {
					no_esObjetivo = false;
				}
			}
			
			// voy paso por paso actualizando Q(s,a) hacia atras en el ep guardado
			Iterator it = episodio.iterator();
			while (it.hasNext()) {
				ParAccionEstado paso = (ParAccionEstado)it.next();
				Estado estado = paso.getEstado();
				int accion = paso.getAccion();
				float r = mundo.getReward(estado.getX(), estado.getY(), accion);
				this.setQValor(estado.getX(), estado.getY(), accion,
								r + gamma*getQValorMax(estadoActual.getX(),estadoActual.getY()));
				estadoActual = estado;
			}
			
			
		}
	}
	
	
	int getQValorMaxDir(int i, int j) {

		if (i == 0 && j == 0) {
			if (getQValor(i,j,1) > getQValor(i,j,2) ) {
				return 1;
			} else {
				return 2;
			}
		} else if(i == 0 && j == 5){
			if (getQValor(i,j,3) > getQValor(i,j,2) ) {
				return 3;
			} else {
				return 2;
			}
		} else if(i == 5 && j == 0) {
			if (getQValor(i,j,0) > getQValor(i,j,1) ) {
				return 0;
			} else {
				return 1;
			}
		} else if(i == 5 && j == 5){
			if (getQValor(i,j,0) > getQValor(i,j,3) ) {
				return 0;
			} else {
				return 3;
			}	
		} else if (i == 0) {
			int maximo = 1;
			float qMaximo = getQValor(i, j, 1);
			for(int it = 2; it < 4; it++){
				if (qMaximo < getQValor(i, j, it)) {
					qMaximo = getQValor(i, j, it);
					maximo = it;
				}
			}
			return maximo;			
		} else if (i == 5) {
			int maximo = 3;
			float qMaximo = getQValor(i, j, 3);
			for(int it = 0; it < 2; it++){
				if (qMaximo < getQValor(i, j, it)) {
					qMaximo = getQValor(i, j, it);
					maximo = it;
				}
			}
			return maximo;		
		} else if (j == 0) {
			int maximo = 0;
			float qMaximo = getQValor(i, j, 0);
			for(int it = 1; it < 3; it++){
				if (qMaximo < getQValor(i, j, it)) {
					qMaximo = getQValor(i, j, it);
					maximo = it;
				}
			}
			return maximo;
		} else if (j == 5) {
			int maximo = 0;
			float qMaximo = getQValor(i, j, 0);
			for(int it = 2; it < 4; it++){
				if (qMaximo < getQValor(i, j, it)) {
					qMaximo = getQValor(i, j, it);
					maximo = it;
				}
			}
			return maximo;
		} else {
			int maximo = 0;
			float qMaximo = getQValor(i, j, 0);
			for(int it = 1; it < 4; it++){
				if (qMaximo < getQValor(i, j, it)) {
					qMaximo = getQValor(i, j, it);
					maximo = it;
				}
			}
			return maximo;	
		}		
	}
	
	
	void imprimirQValores(int i, int j, Mundo mundo){
		for(int it = 0; it < i; it++){
			for(int it2 = 0; it2 < j; it2++){
//				System.out.println(it + " " + it2 + " " + tabla[it][it2][0] + " arriba"); // arriba
//				System.out.println(it + " " + it2 + " " + tabla[it][it2][1] + " derecha"); // derecha
//				System.out.println(it + " " + it2 + " " + tabla[it][it2][2] + " abajo"); // abajo
//				System.out.println(it + " " + it2 + " " + tabla[it][it2][3] + " izquierda"); // izquierda
				if (!mundo.getEsGoal(new Estado(it,it2))) {
					System.out.println(it + " " + it2 + " " + this.getQValorMaxDir(it,it2));
				}
			}
		}		
	}
	
	
	
	
}
